﻿#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDF.h"
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/objects.h>
#include <openssl/err.h>
#include <openssl/applink.c>
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")

unsigned char key[][16] = { { 0xd4,0x2c,0x65,0xe1,0x8a,0xc4,0xcc,0x35,0xa6,0xbf,0x9d,0x74,0xea,0x76,0xda,0x22 },
							{ 0x6d,0x51,0x00,0x2b,0xb6,0xe3,0x85,0xe0,0x98,0xd3,0x69,0xba,0xfc,0xd1,0xc1,0x4a },
							{ 0x6d,0x98,0xd2,0x14,0x76,0xa4,0xa2,0x90,0x4e,0x2c,0x68,0x1a,0x27,0xf3,0xd8,0x0d } };

int SDF_Encrypt(void* hSessionHandle, void* hKeyHandle, unsigned int uiAlgID, unsigned char* pucIV,
	unsigned char* pucData, unsigned int uiDataLength,
	unsigned char* pucEncData, unsigned int* puiEncDataLength)
{

	EVP_CIPHER_CTX* ctx;
	ctx = EVP_CIPHER_CTX_new();
	unsigned char hkey[16];
	if ((int)hKeyHandle < 0 || (int)hKeyHandle > 2)
	{
		return SDR_KEYNOTEXIST;
	}
	else
	{
		for (int i = 0; i < 16; i++)
		{
			hkey[i] = key[(int)hKeyHandle][i];
		}
	}
	int outl;
	int outltmp;
	int rv;

	EVP_CIPHER_CTX_init(ctx);
	switch (uiAlgID)
	{
	case SGD_SM4_ECB:
	{
		rv = EVP_EncryptInit_ex(ctx, EVP_sm4_ecb(), NULL, hkey, pucIV);
		break;
	}
	case SGD_SM4_CBC:
	{
		rv = EVP_EncryptInit_ex(ctx, EVP_sm4_cbc(), NULL, hkey, pucIV);
		break;
	}
	case SGD_SM4_CFB:
	{
		rv = EVP_EncryptInit_ex(ctx, EVP_sm4_cfb(), NULL, hkey, pucIV);
		break;
	}
	default:
		return SDR_ALGNOTSUPPORT;
	}
	if (rv != 1)
	{
		return SDR_INARGERR;
	}
	rv = EVP_EncryptUpdate(ctx, pucEncData, &outl, pucData, uiDataLength);
	if (rv != 1)
	{
		return SDR_SYMOPERR;
	}
	rv = EVP_EncryptFinal_ex(ctx, pucEncData + outl, &outltmp);
	if (rv != 1)
	{
		return SDR_OUTARGERR;
	}
	*puiEncDataLength = outl + outltmp;
	return 0;
}
int SDF_Decrypt(void* hSessionHandle, void* hKeyHandle, unsigned int uiAlgID, unsigned char* pucIV,
	unsigned char* pucEncData, unsigned int uiEncDataLength,
	unsigned char* pucData, unsigned int* puiDataLength)
{
	EVP_CIPHER_CTX* ctx;
	ctx = EVP_CIPHER_CTX_new();
	unsigned char hkey[16];
	if ((int)hKeyHandle < 0 || (int)hKeyHandle > 2)
	{
		return SDR_KEYNOTEXIST;
	}
	else
	{
		for (int j = 0; j < 16; j++)
		{
			hkey[j] = key[(int)hKeyHandle][j];
		}
	}
	int outl;
	int outltmp;
	int rv;

	EVP_CIPHER_CTX_init(ctx);
	switch (uiAlgID)
	{
	case SGD_SM4_ECB:
	{
		rv = EVP_DecryptInit_ex(ctx, EVP_sm4_ecb(), NULL, hkey, pucIV);
		break;
	}
	case SGD_SM4_CBC:
	{
		rv = EVP_DecryptInit_ex(ctx, EVP_sm4_cbc(), NULL, hkey, pucIV);
		break;
	}
	case SGD_SM4_CFB:
	{
		rv = EVP_DecryptInit_ex(ctx, EVP_sm4_cfb(), NULL, hkey, pucIV);
		break;
	}
	default:
		return SDR_ALGNOTSUPPORT;
	}
	if (rv != 1)
	{
		return SDR_INARGERR;
	}
	rv = EVP_DecryptUpdate(ctx, pucData, &outl, pucEncData, uiEncDataLength);
	if (rv != 1)
	{
		return SDR_SYMOPERR;
	}
	rv = EVP_DecryptFinal_ex(ctx, pucData + outl, &outltmp);
	if (rv != 1)
	{
		return SDR_OUTARGERR;
	}
	*puiDataLength = outl + outltmp;
	return 0;
}

int SDF_CalculateMAC(void* hSessionHandle, void* hKeyHandle, unsigned int uiAlgID, unsigned char* pucIV,
	unsigned char* pucData, unsigned int uiDataLength,
	unsigned char* pucMAC, unsigned int* puiMACLength)
{
	HMAC_CTX* ctx;
	ctx = HMAC_CTX_new();
	int rv;

	unsigned char hkey[16];
	if ((int)hKeyHandle < 0 || (int)hKeyHandle > 2)
	{
		return SDR_KEYNOTEXIST;
	}
	else
	{
		for (int j = 0; j < 16; j++)
		{
			hkey[j] = key[(int)hKeyHandle][j];
		}
	}
	HMAC_CTX_reset(ctx);
	rv = HMAC_Init_ex(ctx, hkey, 16, EVP_sm3(), NULL);
	if (rv != 1)
	{
		return SDR_INARGERR;
	}
	rv = HMAC_Update(ctx, pucData, uiDataLength);
	if (rv != 1)
	{
		return SDR_MACERR;
	}
	rv = HMAC_Final(ctx, pucMAC, puiMACLength);
	if (rv != 1)
	{
		return SDR_OUTARGERR;
	}
	HMAC_CTX_free(ctx);
	return 0;
}
